﻿Imports XMLmosaic_Interpreter.Arithmetic

''' <summary>
''' Processes mathematical functions.
''' </summary>
''' <remarks></remarks>
Module Math

    ''' <summary>
    ''' Instance of the Arithmetic Class.
    ''' </summary>
    ''' <remarks></remarks>
    Dim Arit As New XMLmosaic_Interpreter.Arithmetic

    ''' <summary>
    ''' The output of the latest math function performed.
    ''' </summary>
    ''' <remarks></remarks>
    Public Ans As String

    ''' <summary>
    ''' Indicates of evaluations are to be carried out.
    ''' </summary>
    ''' <remarks></remarks>
    Public DoEval As Boolean = True


    ''' <summary>
    ''' Begins teh processing of the maths expression.
    ''' </summary>
    ''' <param name="expr">The math expression to execute.</param>
    ''' <remarks></remarks>
    Sub MathExpr(ByVal expr As String)

        Dim exprsplit As String() = expr.Split(New [Char]() {" "c})

        Dim len As Integer = exprsplit.Length - 1
        Dim i As Integer = -1

        Dim output As String = ""

        Do Until i = len
            i = i + 1
            If exprsplit(i) Like "*.*(*" Or exprsplit(i) Like "*(*" Then

                Dim arr As String = ""

                If exprsplit(i) Like "*.*(*)" Or exprsplit(i) Like "*(*)" Then
                    arr = exprsplit(i)
                Else
                    arr = exprsplit(i)
                    Do Until exprsplit(i) Like "*)*"
                        i = i + 1

                        arr = arr & exprsplit(i)
                    Loop
                End If

                arr = arr.Trim()

                Relations.MakeVar = True
                Relations.Input(arr)
                Relations.MakeVar = False

                arr = GetVal(Relations.CurrentMethod)

                output = output & arr & " "
            ElseIf exprsplit(i) Like "Sqrt|*" Then
                Dim split As String() = exprsplit(i).Split(New [Char]() {"|"c})
                If split(1) Like "[A-Z]*" Or split(1) Like "[a-z]*" Or split(1) Like "[A-Z]" Or split(1) Like "[a-z]" Then
                    split(1) = split(1).Trim()
                    Dim val As Double = CDbl(GetVal(split(1)))
                    output = output & System.Math.Sqrt(val) & " "
                Else
                    output = output & System.Math.Sqrt(split(1)) & " "
                End If
            ElseIf exprsplit(i) Like "Pi|*" Or exprsplit(i) Like "Pi|" Then
                output = output & CStr(System.Math.PI) & " "
            ElseIf exprsplit(i) Like "[A-Z]*" Or exprsplit(i) Like "[a-z]*" Or exprsplit(i) Like "[A-Z]" Or exprsplit(i) Like "[a-z]" And exprsplit(i) Like "Sqrt|*" = False Then
                output = output & GetVal(exprsplit(i)) & " "
            Else
                output = output & exprsplit(i) & " "
            End If
        Loop

        output = output.Trim()
        EvalMath(output)

    End Sub

    ''' <summary>
    ''' Evaluates the / and * parts of the expression.
    ''' </summary>
    ''' <param name="expr">The expression to process.</param>
    ''' <remarks></remarks>
    Sub EvalMath(ByVal expr As String)

        expr = expr.Trim()

        If expr.EndsWith("*") Or expr.EndsWith("/") Then
            GoTo Last
        End If
        If expr.EndsWith("+") Or expr.EndsWith("-") Then
            GoTo Last
        End If

        Dim exprsplit As String() = expr.Split(New [Char]() {" "c})

        Dim len As Integer = exprsplit.Length - 1
        Dim i As Integer = -1

        Dim output As String = ""

       

        If (expr.Contains(" * ") = False And expr.Contains(" / ") = False) Then
            expr = expr.Trim()
            EvalMath2(expr)
        End If


        Do Until i = len


            i = i + 1
            
            If len = 0 Then
                output = expr
                output = output.Trim()
                GoTo Final
            End If

            exprsplit(i) = exprsplit(i).Trim()

            If DoEval = True Then
                If (i + 1) > len Or i = len Or i > len Then
                Else
                    If exprsplit(i + 1) = "*" Or exprsplit(i + 1) = "/" Or exprsplit(i) = "*" Or exprsplit(i) = "/" Then

                        If exprsplit(i) = "*" Or exprsplit(i) = "/" Then

                            Dim op As String = exprsplit(i)
                            Dim lval As String = exprsplit(i - 1)
                            Dim rval As String = exprsplit(i + 1)

                            lval = lval.Trim()
                            rval = rval.Trim()

                            Dim subexpr As String = lval & " " & op & " " & rval

                            output = output & eval(subexpr) & " "
                            i = i + 2

                            DoEval = False

                            If i > len Then
                                i = len
                                DoEval = True
                            End If
                        End If

                    Else
                        output = output & exprsplit(i) & " "
                    End If

                End If
            End If


            If DoEval = False Then
                output = output & exprsplit(i) & " "
            End If

        Loop

        DoEval = True

Final:

        If output.Contains(" * ") = True Or output.Contains(" / ") = True Then
            output = output.Trim()
            EvalMath(output)
        Else
            output = output.Trim()
            EvalMath2(output)
        End If
Last:
    End Sub

    ''' <summary>
    ''' Continues the processing of + and - parts of the expression.
    ''' </summary>
    ''' <param name="expr">The expresson to process.</param>
    ''' <remarks></remarks>
    Sub EvalMath2(ByVal expr As String)

        expr = expr.Trim()

        If expr.EndsWith("+") Or expr.EndsWith("-") Then
            GoTo Last
        End If

        Dim exprsplit As String() = expr.Split(New [Char]() {" "c})

        Dim len As Integer = exprsplit.Length - 1
        Dim i As Integer = -1

        Dim output As String = ""

        If (expr.Contains(" + ") = False And expr.Contains(" - ") = False) Then
            expr = expr.Trim()
            output = expr
            GoTo Final
        End If


        Do Until i = len
            i = i + 1

            If len = 0 Then
                output = expr
                output = output.Trim()
                GoTo Final
            End If


            exprsplit(i) = exprsplit(i).Trim()
            If DoEval = True Then

                If (i + 1) > len Or i = len Or i > len Then
                Else
                    If exprsplit(i + 1) = "+" Or exprsplit(i + 1) = "-" Or exprsplit(i) = "+" Or exprsplit(i) = "-" Then

                        If exprsplit(i) = "+" Or exprsplit(i) = "-" Then

                            Dim op As String = exprsplit(i)
                            Dim lval As String = exprsplit(i - 1)
                            Dim rval As String = exprsplit(i + 1)

                            lval = lval.Trim()
                            rval = rval.Trim()

                            Dim subexpr As String = lval & " " & op & " " & rval

                            output = output & eval(subexpr) & " "
                            i = i + 2

                            DoEval = False

                            If i > len Then
                                i = len
                                DoEval = True
                            End If
                        End If

                    Else
                        output = output & exprsplit(i) & " "
                    End If

                End If
            End If


            If DoEval = False Then
                output = output & exprsplit(i) & " "
            End If

        Loop

        DoEval = True
        If exprsplit(i) = "+" Or exprsplit(i) = "-" Then

            Dim op As String = exprsplit(i)
            Dim lval As String = exprsplit(i - 1)
            Dim rval As String = exprsplit(i + 1)

            lval = lval.Trim()
            rval = rval.Trim()

            Dim subexpr As String = lval & " " & op & " " & rval

            output = output & eval(subexpr) & " "
            i = i + 2

            DoEval = False

            If i > len Then
                i = len
                DoEval = True
            End If
        End If
Final:

        If output.Contains(" + ") = True Or output.Contains(" - ") = True Then
            output = output.Trim()
            EvalMath2(output)
        Else
            output = output.Trim()
            Ans = output
            If Ans = "" Then
                Ans = 0
            End If
            ' MsgBox(Ans)
        End If
Last:

    End Sub

    ''' <summary>
    ''' Does + - * and / given the operator and operands.
    ''' </summary>
    ''' <param name="expr">The expression to process.</param>
    ''' <returns>The answer of the answer of the function.</returns>
    ''' <remarks></remarks>
    Function eval(ByVal expr As String) As Double
        expr = expr.Trim

        Dim exprsplit As String() = expr.Split(New [Char]() {" "c})
        Dim out As Double

        exprsplit(0) = exprsplit(0).Trim
        exprsplit(2) = exprsplit(2).Trim

        If exprsplit(1) = "*" Then
            out = Arit.Multiply(CDbl(exprsplit(0)), CDbl(exprsplit(2)))
        ElseIf exprsplit(1) = "/" Then
            out = Arit.Divide(CDbl(exprsplit(0)), CDbl(exprsplit(2)))
        ElseIf exprsplit(1) = "+" Then
            out = Arit.Add(CDbl(exprsplit(0)), CDbl(exprsplit(2)))
        ElseIf exprsplit(1) = "-" Then
            out = Arit.Subtract(CDbl(exprsplit(0)), CDbl(exprsplit(2)))
        End If

        Return out
    End Function

End Module
